#pragma once
#include <vector>
#include <queue>
#include <pthread.h>
namespace xyl
{
    const size_t DEFAULT_THREAD_NUM = 5;

    // START OF CLASS __ThreadPool
    template <typename T>
    class __ThreadPool
    {
    public:
        __ThreadPool(size_t threadNum = DEFAULT_THREAD_NUM)
            : _threadNum(threadNum), _threads(threadNum)
        {
            pthread_mutex_init(&_mtx, nullptr);
            pthread_cond_init(&_cond, nullptr);
            std::cout << "__ThreadPool 初始化完毕..\n";
        }
        ~__ThreadPool()
        {
            pthread_mutex_destroy(&_mtx);
            pthread_cond_destroy(&_cond);
            std::cout << "__ThreadPool 析构完毕..\n";
        }

        void __start()
        {
            for (int i = 0; i < _threadNum; ++i)
                pthread_create(&_threads[i], nullptr, __consume, this);
            std::cout << "__ThreadPool::start() 调用完毕..\n";
        }

        /*
            生产任务由外部的生产者执行。
            多个生产者可能同时访问_tasks队列，故加锁
        */
        void __push_task(const T &task)
        {
            __lock_tasks();
            _tasks.push(task);
            __wake_up_consumer(); // 生产数据后，唤醒消费者过来消费
            __unlock_tasks();
        }

    public:
        void __lock_tasks() { pthread_mutex_lock(&_mtx); }
        void __unlock_tasks() { pthread_mutex_unlock(&_mtx); }
        void __block_consumer() { pthread_cond_wait(&_cond, &_mtx); }
        void __wake_up_consumer() { pthread_cond_signal(&_cond); }
        bool __tasks_is_empty() { return _tasks.empty(); }
        /*
            获取任务是由消费者执行的，即该类中的_threads。
            且该动作是在临界区(已加锁)内执行的，故不用加锁。
        */
        T __pop_task()
        {
            T t = _tasks.front();
            _tasks.pop();
            return t;
        }
        // 消费者，处理线程池任务队列内的任务
        static void *__consume(void *args)
        {
            pthread_detach(pthread_self());
            __ThreadPool<T> *tp = static_cast<__ThreadPool<T> *>(args);
            while (true)
            {
                // 加锁  -- 检查是否有任务，有则取任务，无则挂起等待 -- 解锁
                tp->__lock_tasks();
                while (tp->__tasks_is_empty())
                    tp->__block_consumer();
                T t = tp->__pop_task();
                tp->__unlock_tasks();
                // 处理任务
                int res = t();
                std::cout << "处理任务结束." << std::endl;
                std::cout << t.format() << " = " << res << std::endl;
            }
        }

    private:
        size_t _threadNum;               // 线程数量
        std::vector<pthread_t> _threads; // 存放线程id
        std::queue<T> _tasks;            // 任务队列
        pthread_mutex_t _mtx;
        pthread_cond_t _cond;
    };
    // END OF CLASS __ThreadPool
}